/* 
 * File:   Box2DNode.cpp
 * Author: aljosa
 * 
 * Created on May 31, 2010, 10:25 PM
 */

#include "Box2DNode.h"
#include "World2D.h"

#include "RenderingSystem.h"

#include "MathUtil.h"

namespace xEngine
{
    namespace PlatformIndependent
    {
        // Constructor
        Box2DNode::Box2DNode(b2World *world) {
            this->world = world; // Set pointer to world
            this->body = NULL;
            this->shapeDef = NULL;
            this->bodyDef = NULL;
            this->shapeData = NULL;
        }

        Box2DNode::~Box2DNode() {
        }

        //
        // Init functions
        //
        void Box2DNode::init() { // Default
            this->bodyDef = new b2BodyDef;
            this->createShape();
            this->shapeData = new b2Vec2(2.0f, 2.0f); // Set shape data as rect, 2x2
        }

        void Box2DNode::init( const b2Vec2 &size, const b2Vec2 &pos ) { // Init as rectangle
            this->bodyDef = new b2BodyDef;
            this->createShape( size, pos );
            this->shapeData = new b2Vec2(size.x, size.y); // Set shape data (width and height)

        }

        void Box2DNode::init( float radius, const b2Vec2 &pos ) { // Init as circle
            this->bodyDef = new b2BodyDef;
            this->createShape( radius, pos );
        }

        // Create default shape
        void Box2DNode::createShape() {
            // DEFAULT: Create rectangle shape

            // Create shape object
            this->shapeDef = new b2PolygonDef();

            // Set dimensions
            ( (b2PolygonDef*)this->shapeDef )->SetAsBox(SCREEN_TO_WORLD(2.0f), SCREEN_TO_WORLD(2.0f));

            // Set position
            this->bodyDef->position.Set(SCREEN_TO_WORLD(0.0f), SCREEN_TO_WORLD(0.0f));

            // Physical properties
            this->shapeDef->density = 1.0f; // Default
            this->shapeDef->restitution = 0.75f;
          //  ( (b2CircleDef*)this->shape )->radius = 32.0f;
        }

        // Create rectangle shape
        void Box2DNode::createShape( const b2Vec2 &size, const b2Vec2 &pos ) {
            // DEFAULT: Create rectangle shape

            // Create shape object
            this->shapeDef = new b2PolygonDef();

            // Set dimensions
            ( (b2PolygonDef*)this->shapeDef )->SetAsBox(SCREEN_TO_WORLD(size.x), SCREEN_TO_WORLD(size.y));
            
            // Set position
            this->bodyDef->position.Set(SCREEN_TO_WORLD(pos.x), SCREEN_TO_WORLD(pos.y));

            // Physical properties
            this->shapeDef->density = 1.0f; // Default
            this->shapeDef->restitution = 0.75f;
          //  ( (b2CircleDef*)this->shape )->radius = 32.0f;
        }

        // Create circle shape
        void Box2DNode::createShape( const float radius, const b2Vec2 &pos ) {
            // DEFAULT: Create rectangle shape

            // Create shape object
            this->shapeDef =  new b2CircleDef();

            // Set dimensions
            ( (b2CircleDef*)this->shapeDef )->radius = radius;

            // Set position
            this->bodyDef->position.Set(SCREEN_TO_WORLD(pos.x), SCREEN_TO_WORLD(pos.y));

            // Physical properties
            this->shapeDef->density = 1.0f; // Default
            this->shapeDef->restitution = 0.75f;
          //  ( (b2CircleDef*)this->shape )->radius = 32.0f;
        }

        void Box2DNode::appear(bool dynamic) {

            this->body = this->world->CreateBody( this->bodyDef );
            this->body->CreateShape( this->shapeDef );
         //   this->body->SetUserData(NULL);

            // Body is dynamic only when it's mass is set.
            if (dynamic)
                 body->SetMassFromShapes();

        }


        // Overloaded from SceneNode
        void Box2DNode::draw(double deltaTime) { // Default wire draw

            glPushMatrix();
           // glRotatef ( -Rad2Deg( this->bodyDef->angle ), 0.0f, 0.0f, 1.0f );
            
            glTranslatef (WORLD_TO_SCREEN( this->body->GetXForm().position.x), WORLD_TO_SCREEN(this->body->GetXForm().position.y), 0.0f);
            glRotatef ( Rad2Deg( this->body->GetAngle() ), 0.0f, 0.0f, 1.0f );
          //  glTranslatef (WORLD_TO_SCREEN( this->body->GetXForm().position.x - ((b2Vec2*)shapeData)->x/2 ), WORLD_TO_SCREEN(this->body->GetXForm().position.y - ((b2Vec2*)shapeData)->y/2 ), 0.0f);
            xEngine::Renderer::RenderingSystem::get()->Box2DRender.DrawSolidPolygon(((b2PolygonDef*)shapeDef)->vertices, ((b2PolygonDef*)shapeDef)->vertexCount, b2Color(0.0, 0.0, 1.0)  ); //DrawCircle( (b2CircleShape*)shape->GetLocalPosition(),
            xEngine::Renderer::RenderingSystem::get()->Box2DRender.DrawPolygon(((b2PolygonDef*)shapeDef)->vertices, ((b2PolygonDef*)shapeDef)->vertexCount, b2Color(1.0, 0.0, 0.0)  ); //DrawCircle( (b2CircleShape*)shape->GetLocalPosition(),

            glPopMatrix();

            xEngine::PlatformIndependent::SceneNode::draw(deltaTime);
        }

        void Box2DNode::release() {

            // Destroy body
            if ( this->body != NULL && this->world != NULL ) {
                this->world->DestroyBody(body);
                cout<<"WORLD DESTROYED BODY"<<endl;

                // Is this right?

                if ( this->bodyDef ) {
                    delete this->bodyDef;
                    this->bodyDef = NULL;
                }

                if ( this->shapeDef ) {
                    delete this->shapeDef;
                    this->shapeDef = NULL;
                }

                if ( this->shapeData ) {
                    delete this->shapeData;
                    this->shapeData = NULL;
                }


                this->body = NULL;
            }

            // Release shape data, if present
            if ( this->shapeData != NULL ) {
                delete this->shapeData;
                this->shapeData = NULL;
            }

            SceneNode::release();

            // TODO: Box2D release
        }
    }
}

